package com.lightsh.gui;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import org.jbox2d.dynamics.World;

import com.lightsh.configure.Configure;
import com.lightsh.interfaces.creator.IBodyCreator;
import com.lightsh.interfaces.listener.ITouchListener;
import com.lightsh.object.BaseObject;
import com.lightsh.test.PerformanceTester;
import com.lightsh.utility.Utility;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.hardware.SensorEvent;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.Vibrator;
import android.view.KeyEvent;
import android.view.MotionEvent;

/**
 * 游戏界面的基类
 * <br/>该类主要进行一些虚方法的定义
 * <br/>该类定义其子类需要实现的方法(包括图形绘制和事件响应)，子类需要实现这些方法来做具体的绘制、响应操作
 * @author Light
 *
 */
public abstract class BaseScreen {
	
	// 屏幕的高宽,以px为单位
	protected int mScreenW;
	protected int mScreenH;
	
	protected Context mContext;
	
	/**
	 * android应用主线程(UI)线程的消息句柄，凡是android内部控件的显示都要使用该句柄，如Toast、AlertDialog等
	 */
	protected Handler mUiThreadHandler;
	protected Paint mPaint;
	protected Matrix mMatrix;
	
	protected Bitmap mBackground;
	protected int mBackgroundW;
	protected int mBackgroundH;
	protected int mBackgroundColor = Color.BLACK;
	
	protected boolean mbPause = false;
	
	protected boolean mbEnd = false;
	
	protected static Random mRand = new Random();
	
	private Vibrator mVibrator;
	
	private List<ITouchListener> mTouchListener;	
	private List<BaseObject> mSurfaceObjects;
	private List<IBodyCreator> mCreators;

	private float mTimeStep = 1 / Configure.PHYSICS_TIME_STEP;
	/**
	 * 重力感应相关
	 */
	protected boolean mSensorEnable = false;
	protected float mXGravity;
	protected float mYGravity;
	protected float mZGravity;
	
	protected PerformanceTester mPerTester;
	protected boolean mEnablePerTest = true;
	
	/**
	 * 
	 * 需要传入context 和 screen的高度和宽度进行初始化
	 */
	public BaseScreen(Context context, int screenW, int screenH) {
		this.mContext = context;
		mUiThreadHandler = new Handler(mContext.getMainLooper());
		mPaint = new Paint();
		mMatrix = new Matrix();
		mPaint.setAntiAlias(true);
		mPaint.setTextSize(18);
		mPaint.setColor(Color.BLUE);
		mPaint.setStyle(Style.FILL);
		
		// 初始化高宽
		mScreenW = screenW;
		mScreenH = screenH;
		
		mTouchListener = Collections.synchronizedList(new ArrayList<ITouchListener>());
		mSurfaceObjects = Collections.synchronizedList(new ArrayList<BaseObject>());
		mCreators = Collections.synchronizedList(new ArrayList<IBodyCreator>());
		
		mPerTester = new PerformanceTester();
	}

	/**
	 * 请在该方中实现游戏所有数据的更新操作
	 * <br/>该方法会在draw之前调用
	 */
	protected abstract void onUpdate();

	/**
	 * 请在该方法中实现游戏的画面绘制操作
	 * <br/>在该方法调用完后，会调用
	 * @param canvas	需要绘制的目标画布
	 */
	protected abstract void onDraw(Canvas canvas);
	
	/**
	 * 该方法中绘制视图表面的物体，例如按钮等控件,这个绘制会方法{@link #onDraw(Canvas)}之后
	 * <br/>请将这里的物体与游戏中的物体区分开，这里的物体一般是与游戏画面没有关系的物体,并且一般是不会跟着屏幕的缩放和移动变化的
	 * @param canvas
	 */
	protected void onDrawSurface(Canvas canvas){
		Rect rect = new Rect(0, 0, mScreenW, mScreenH);
		for(BaseObject object : mSurfaceObjects){
			object.draw(canvas, rect);
		}
	}
	protected void onUpdateSurface(){
		for(BaseObject object : mSurfaceObjects){
			object.update();
		}
	}
	
	public void update(){
		doCreate();
		onUpdate();
		onUpdateSurface();
		onUpdateTester();
	}
	protected void onUpdateTester(){
		if(mEnablePerTest){
			mPerTester.nextFPS();
		}
	}
	public void draw(Canvas canvas){
		onDraw(canvas);
		onDrawSurface(canvas);
		// 清除屏幕边沿，否则可能有部分运动的图形绘制到边界外(这里是否有必要？)
		if(canvas.getWidth() > mScreenW){
			canvas.drawRect(new Rect(mScreenW, 0, canvas.getWidth(), canvas.getHeight()), mPaint);
		}
		if(canvas.getHeight() > mScreenH){
			canvas.drawRect(new Rect(0, mScreenH, canvas.getWidth(), canvas.getHeight()), mPaint);
		}
		onDrawTester(canvas);
	}
	
	protected void onDrawTester(Canvas canvas){
		if(mEnablePerTest){
			mPerTester.drawPerformanceInfo(canvas, null);
		}
	}

	/**
	 * 在该方法中处理用户的动作
	 * @param event		用户事件
	 * @return			是否消耗了该事件
	 */
	public boolean onTouchEvent(MotionEvent event){
		return objectHandleTouchEvent(event);
	}

	/**
	 * 在该方法中处理用户的按下动作
	 * @param keyCode
	 * @param event
	 * @return
	 */
	public abstract boolean onKeyDown(int keyCode, KeyEvent event);

	/**
	 * 在该方法中处理用户的放开动作
	 * @param keyCode
	 * @param event
	 * @return
	 */
	public abstract boolean onKeyUp(int keyCode, KeyEvent event);

	/**
	 * 设置用于绘制的paint的颜色
	 * @param color		需要设置的颜色值
	 */
	public void setPaintColor(int color) {
		int red = (color & 0xff0000) >> 16;
		int green = (color & 0x00ff00) >> 8;
		int blue = (color & 0x0000ff);
		mPaint.setColor(Color.rgb(red, green, blue));
	}

	/**
	 * 获取当前screen的宽度,以px为单位
	 */
	public int getScreenWidth() {
		return mScreenW;
	}

	/**
	 * 获取当前屏幕的高度,以px为单位
	 */
	public int getScreenHeight() {
		return mScreenH;
	}
	
	/**
	 * 当游戏界面被隐藏时，调用该函数。注意，这个方法后，{@link #onUpdate()}和 {@link #onDraw(Canvas)}都会停止,直到界面再次被显示
	 *<br/>或许你有些数据需要在这里重置。如: 性能测试时的FPS计算
	 *<br/>注意，只会有pause消息而不会有resume；你可以在下一个{@link #onUpdate()}时认为是resume
	 *
	 */
	public void onScreenPause(){
		if(mEnablePerTest){
			mPerTester.reset();		
		}
	}
	
	/**
	 * 暂停游戏。
	 * <br/>注意，这里暂停游戏的{@link #onUpdate()}，但是{@link #onDraw(Canvas)}还是会继续的
	 */
	public void pause(){
		mbPause = true;
	}
	
	/**
	 * 恢复游戏
	 */
	public void resume(){
		mbPause = false;
	}
	
	public boolean isPause(){
		return mbPause;
	}
	
	/**
	 * 设置需要绘制的背景图
	 * @param bitmap
	 */
	public void setBackgroundBitmap(Bitmap bitmap){
		mBackground = bitmap;
		mBackgroundW = mBackground.getWidth();
		mBackgroundH = mBackground.getHeight();
	}
	
	public void setBackgroundColor(int color){
		mBackgroundColor = color;
	}
	
	public void vibrate(long milliseconds){
		if(mVibrator == null){
			mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
		}
		mVibrator.vibrate(milliseconds);
	}
	
	public void addTouchListener(ITouchListener listener){
		synchronized (mTouchListener) {
			mTouchListener.add(listener);
		}
	}
	private void clearTouchListener(){
		synchronized (mTouchListener) {
			mTouchListener.clear();
		}

	}
	
	public void addSurfaceObject(BaseObject object){
		synchronized (mSurfaceObjects) {
			mSurfaceObjects.add(object);
		}
	}
	private void clearAllSurfaceObject(){
		synchronized (mSurfaceObjects) {
			mSurfaceObjects.clear();
		}
	}
	
	private boolean objectHandleTouchEvent(MotionEvent ev){
		
		// FIXME 优化这里
		Utility.fixme();
		int currentLevel = -1;
		int nextLevel = 0;
		int level = 0;
		final float positionX = getScreenPositionX();
		final float positionY = getScreenPositionY();
		final float worldScale = getScreenScale();
		while(currentLevel != nextLevel){
			currentLevel = nextLevel;
			for(ITouchListener listener : mTouchListener){
				level = listener.getTouchLevel();
				if(level == currentLevel){
					if(listener.onTouchEvent(ev, worldScale, positionX, positionY)){
						return true;
					}
				}else if(level > currentLevel){
					// 记录与currentLevel最接近的下一个level
					if(currentLevel == nextLevel || nextLevel > level){
						nextLevel = level;
					}
				}
			}
		}
		return false;
	}
	
	/**
	 * 添加body到screen的队列中,screen会在下一次update时调用{@link #create()}方法来创建物体
	 */
	public void addBodyToScreen(IBodyCreator creator){
		synchronized (mCreators) {
			mCreators.add(creator);
		}
	}
	private void cleanCreator(){
		synchronized (mCreators) {
			mCreators.clear();
		}
	}
	private void doCreate(){
		synchronized (mCreators) {
			if(!mCreators.isEmpty()){
				for(IBodyCreator creator : mCreators){
					creator.create();
				}
				mCreators.clear();
			}
		}
	}
	
	public boolean isEnd(){
		return mbEnd;
	}
	
	public boolean isSensorEnable(){
		return mSensorEnable;
	}
	public void enableSensor(boolean enable){
		mSensorEnable = enable;
	}
	
	public void onSensorChange(SensorEvent event){
		if(mSensorEnable){
			float x = event.values[SensorManager.DATA_X];
			float y = event.values[SensorManager.DATA_Y];
			float z = event.values[SensorManager.DATA_Z];
			
			// 如果是横屏，这里会x/y会相反
			mXGravity = y;
			mYGravity = x;
			mZGravity = z;
		}
	}	
	
	public void enablePerTest(boolean enable){
		mEnablePerTest = enable;
	}
	
	public float getTimeStep(){
		return mTimeStep;
	}
	
	public float getScreenPositionX(){
		return 0;
	}
	public float getScreenPositionY(){
		return 0;
	}
	
	/**
	 * 获取屏幕当前缩放比例
	 */
	public float getScreenScale(){
		return 1;
	}
	
	/**
	 * 清空screen内所有的物体
	 * <br/>注意：子类需要负责清空自己特有的物体信息
	 */
	public void clearAllList(){
		clearAllSurfaceObject();
		clearTouchListener();
		cleanCreator();
	}
	
	public void runInUiThread(Runnable runnable){
		mUiThreadHandler.post(runnable);
	}
	public void runInUiThread(Runnable runnable, long delayMillis){
		mUiThreadHandler.postDelayed(runnable, delayMillis);
	}
	public Context getContext(){
		return mContext;
	}
}
